home *** CD-ROM | disk | FTP | other *** search
/ BCI NET 2 / BCI NET 2.iso / archives / programming / source / graphicgems3.lha / GemsIII / scallops8.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-06  |  8.6 KB  |  238 lines

  1. /*----------------------   main() - test_scallops.c   ------------------------
  2. * This main program tests the scallop (i.e. an envelope of circles) generating
  3. *  function by drawing filled circles with a "fill_circle" function and then
  4. *  using an "erode" function to reduce them to their outlines or scallops.
  5. *  It allocates a small frame buffer and asks the user to choose the number
  6. *  of circles desired, their centers, and their radii.  The circles are drawn
  7. *  and filled in sequence.  A simple "printf" to the standard output displays
  8. *  the upper left corner of the frame buffer.  The "erode" function is then
  9. *  applied to the frame buffer, leaving only the outlines of the filled
  10. *  circles (scallops) with their interiors refilled by an erosion replacement
  11. *  value.  Again the upper left corner of the frame buffer is displayed with
  12. *  the results of the eroding the filled circles to scallops.
  13. * When the erosion replacement value is the same as the backbround, only the
  14. *  outlines (the value used for circle filling) will be shown.
  15. *
  16. *    Author:        Eric Furman
  17. *            General Dynamics/ Convair Division
  18. *            San Diego, California
  19. */
  20.  
  21. #include <stdio.h>
  22.  
  23. #define  XMIN        0        /* limits of the frame buffer */
  24. #define  XMAX        63
  25. #define  YMIN        0
  26. #define  YMAX        63
  27. #define  STRIDE        64     /* width of frame buffer (XMAX - XMIN + 1) */
  28.  
  29. #define  MIN(j,k)  (j)<(k) ? (j) : (k)
  30. #define  MAX(j,k)  (j)>(k) ? (j) : (k)
  31.  
  32. unsigned char  *Pt_Frame;      /* Global pointer to start of frame buffer */
  33.  
  34.  
  35. main()
  36. {
  37.   int  xc, yc, r, nx, ny, nc, k, j;
  38.   unsigned char  val_fill, val_erode;
  39.   void  fill_circle(), erode();
  40.  
  41.  
  42. /* Values (i.e. VLT index) for filling the circles and erosion replacement. */
  43.   val_fill = 8;
  44.   val_erode = 1;
  45.  
  46. /* Allocate space initialized to zero for the test frame buffer:  */
  47.   ny = YMAX - YMIN + 1;            /* number of rasters */
  48.   Pt_Frame = (unsigned char *)calloc(STRIDE * ny, sizeof(unsigned char));
  49.  
  50. /* Obtain user input and loop through circles filling each one. */
  51.   printf(" Number of circles: ");
  52.   scanf("%d", &nc);                /* try:  3 */
  53.    for(k=0; k<nc; k++) {
  54.     printf(" center (x,y) and radius:  ");
  55.     scanf("%d%d%d", &xc, &yc, &r);       /* try:  5 5 6,  15 12 7,  28 6 5 */
  56.  
  57. /* Check for total clipping before filling circle:  */
  58.      if(xc+r < XMIN || xc-r > XMAX || yc+r < YMIN || yc-r > YMAX) {
  59.       printf("Circle x,y,r:  %d  %d  %d  total clip.\n", xc, yc, r);
  60.      }
  61.      else {
  62.       fill_circle(xc, yc, r, val_fill);
  63.      }
  64.    }            /* end for loop through circles */
  65.  
  66. /* Print the Upper Left corner of the buffer after filling circles:  */
  67.   printf("UL corner of filled buffer.\n");
  68.    for(k=0; k<23; k++) {
  69.     printf("%2d: ",k);
  70.      for(j=0; j<35; j++) {
  71.       printf("%2d", *(Pt_Frame + j + k * STRIDE));
  72.      }
  73.     printf("\n");
  74.    }
  75.  
  76.   erode(val_fill, val_erode);        /* erode the filled circles */
  77.  
  78. /* Print the Upper Left corner of the buffer after eroding filled circles:  */
  79.   printf("UL corner of eroded buffer.\n");
  80.    for(k=0; k<23; k++) {
  81.     printf("%2d: ",k);
  82.      for(j=0; j<35; j++) {
  83.       printf("%2d", *(Pt_Frame + j + k * STRIDE));
  84.      }
  85.     printf("\n");
  86.    }
  87.  
  88.   free((char*) Pt_Frame);        /* free the frame buffer memory */
  89. }
  90. /*---------------------------   fill_circle()   ----------------------------
  91. * A midpoint circle generating/filling algorithm using second order partial
  92. *   differences to compute cartesian increments.  Given a circles center
  93. *   point (xc,yc), its radius (r), and a fill value (value);  this will
  94. *   draw the filled circle.
  95. */
  96.  
  97. void fill_circle(xc, yc, r, value)
  98.   int  xc, yc, r;                /* center & radius */
  99.   unsigned char  value;                /* filling value */
  100. {
  101.   int x, y, d, de, dse, xl, xr, yt, yb;
  102.   register int  k;
  103.   register unsigned char  *ptb;
  104.   void  raster_fill();
  105.  
  106.   x = 0;
  107.   y = r;            /* initialization */
  108.   d = 1 - r;
  109.   de = 3;
  110.   dse = -2 * r + 5;
  111.    while(y >= x)  {    /* thru 2nd octant, others handled in raster_fill() */
  112.      if(d < 0) {        /* only move +x in octant 2 */
  113.       d += de;
  114.       dse += 2;
  115.       raster_fill(xc, yc, y, x, value);     /* rasters in octants 1-4 & 5-8 */
  116.      }
  117.      else {            /* move +x and -y in octant 2 */
  118.       d += dse;
  119.       dse += 4;
  120.       raster_fill(xc, yc, y, x, value);     /* rasters in octants 1-4 & 5-8 */
  121.       raster_fill(xc, yc, x, y, value);     /* rasters in octants 2-3 & 6-7 */
  122.       y --;
  123.      }
  124.     de += 2;
  125.     x++;
  126.    }                    /* end while(y >= x) */
  127. }
  128. /*------------------------   raster_fill()   ---------------------------------
  129. * Rasters filling for octants 2 to 3 and 6 to 7.  x and y will be reversed in
  130. *   the calling sequence for octants 1 to 4 and 5 to 8.
  131. * Requires the global pointer to a frame buffer (Pt_Frame), the defined
  132. *   parameters for the frame extents (XMIN, XMAX, YMIN, YMAX), and the defined
  133. *   parameter for the frame width (STRIDE).
  134. * Called by the fill_circle function.    
  135. */
  136.  
  137. void raster_fill(xc, yc, x, y, value)
  138.   int  xc, yc, x, y;
  139.   unsigned char  value;
  140. {
  141.   int  xl, xr, yt, yb;
  142.   register int  k;
  143.   register unsigned char  *ptb;
  144.  
  145.   xr = MAX(xc + x, XMIN);             /* raster(s) x limits */
  146.   xl = MIN(xc - x, XMAX);
  147.  
  148. /* if raster segment on frame in x, get y values of top and bottom raster */
  149.    if(xr >= xl) {
  150.     yt = yc + y;
  151.     yb = yc - y;
  152.  
  153. /* if raster seqment on frame in y, point to it's start and fill segment */
  154.      if(yt <= YMAX && yt >= YMIN) {
  155.       ptb = Pt_Frame + yt * STRIDE + xl;
  156.        for(k=xl; k<=xr; k++)  *ptb++ = value;
  157.      }
  158.      if(yb != yt && yb <= YMAX && yb >= YMIN) { /* if on & not same raster */
  159.       ptb = Pt_Frame + yb * STRIDE + xl;
  160.        for(k=xl; k<=xr; k++)  *ptb++ = value;
  161.      }
  162.    }                /* end of if(xr >= xl) */
  163. }
  164. /*--------------------------   erode()   ------------------------------------
  165. * Erode the filled circles to their envelope (scallops) only.  Erases existing
  166. *   val_filled pixels to val_erode when all 4 nearest neighbor pixels are also 
  167. *   set to val_filled.
  168. * Requires the value used to fill the circles (val_filled) and a value to
  169. *   which their interiors will be eroded (val_erode).
  170. * Also requires the global pointer to a frame buffer (Pt_Frame), the defined
  171. *   parameters for the frame extents (XMIN, XMAX, YMIN, YMAX), and the defined
  172. *   parameter for the frame width (STRIDE).
  173. */
  174.  
  175. void erode(val_filled, val_erode)
  176.   unsigned char  val_filled, val_erode;    /* filled and erode to values */
  177. {
  178.   int  k, j;
  179.   unsigned char  *buf0, *buf1, *buf2, *b0, *b1, *b2;
  180.   int  n;
  181.   unsigned char  val4, *ptl, *ptr, *ptb, *ptt, *ptc, *ptf;
  182.  
  183.   val4 = val_filled * 4;        /* for nearest neighbor sum test below */
  184.  
  185. /* Allocate space for working raster buffers were erosion test/evaluation will
  186. *  be performed.  These include a one pixel border beyond the frame buffer. */
  187.   buf0 = b0 = (unsigned char*)malloc((STRIDE+2) * sizeof(unsigned char));
  188.   buf1 = b1 = (unsigned char*)malloc((STRIDE+2) * sizeof(unsigned char));
  189.   buf2 = b2 = (unsigned char*)malloc((STRIDE+2) * sizeof(unsigned char));
  190.   ptt = buf0;
  191.   ptc = buf1;            /* set center, top, and bottom buffer pointers */
  192.   ptb = buf2;
  193.  
  194. /* Initial buffer values to drawing value for one pixel border at top: */
  195.    for(k=0; k<STRIDE+2; k++)  *ptt++ = *ptc++ = *ptb++ = val_filled;
  196.  
  197. /* Initialize first working raster buffer from the Frame buffer */
  198.   ptf = Pt_Frame;
  199.   ptb = buf2 + 1;
  200.    for(k=0; k<STRIDE; k++)  *ptb++ = *ptf++;
  201.  
  202. /* Working through the Frame buffer raster by raster with line counter n:  */
  203.    for(k=YMIN, n=0; k<=YMAX; k++, n++) {
  204.     ptf = buf0;
  205.     buf0 = buf1;
  206.     buf1 = buf2;        /* roll pointers for circular buffering */
  207.     buf2 = ptf;
  208.     ptb = buf2 + 1;                /* "new" buffer line to fill */
  209.      if(k == YMAX) {             /* if below frame, use filled values */
  210.       for(j=0; j<STRIDE+2; j++)  *ptb++ = val_filled;
  211.      }
  212.      else {             /* else on frame buffer, so load from frame */
  213.       ptf = Pt_Frame + (n+1) * STRIDE;
  214.       for(j=0; j<STRIDE; j++)  *ptb++ = *ptf++;      /* add next raster */
  215.      }
  216.  
  217. /* Doing erosion by moving across the three raster buffers by pointers to
  218. * the nearest four neighbors, the center pixel, and the output raster:  */
  219.     ptl = buf1;                    /* left of test point */
  220.     ptr = buf1 + 2;                /* right */
  221.     ptt = buf0 + 1;                /* top */
  222.     ptb = buf2 + 1;                /* bottom */
  223.     ptc = buf1 + 1;                /* center */
  224.     ptf = Pt_Frame + n * STRIDE;        /* output */
  225.      for(j=0; j<STRIDE; j++)  {        /* across buffers pixel by pixel */
  226.        if(*ptc++ == val_filled) {        /* is center pixel value filled */
  227.          if((*ptl + *ptr + *ptt + *ptb) == val4)  *ptf = val_erode;
  228.        }
  229.       ptl++;  ptr++;   ptt++;   ptb++;   ptf++;     /* increment pointers */
  230.      }                   /* end for j loop across raster buffers */
  231.    }                /* end for k loop thru frame buffer rasters */
  232.  
  233.   free((char*)b0);
  234.   free((char*)b1);
  235.   free((char*)b2);
  236. }
  237. /*------------------------------------------------------------------------*/
  238.